using System;
using System.Collections.Generic;


namespace AdvancedTool
{
    /// <summary>
    /// 限制用户输入文本并返回指定选项
    /// </summary>
    public class ConsoleInput
    {
        /// <summary>
        ///
        /// </summary>
        /// <param name="userText">用户输入的错误的文本</param>
        public delegate void InvalidInput(string userText);

        private enum HaveBigSmallOrNone
        {
            Have,
            Big,
            Small,
            None
        }

        private string orgin = "";

        private Dictionary<string, object> AcceptItems = new Dictionary<string, object>();

        /// <summary>
        /// 是否忽略大小写
        /// </summary>
        public bool IsIgnoreCase
        {
            get;
            set;
        }

        /// <summary>
        /// 用户输入原文
        /// </summary>
        public string OrginText => orgin;

        /// <summary>
        /// 默认提示用户输入的提示文本
        /// </summary>
        public string TitleText
        {
            get;
            set;
        }

        /// <summary>
        /// 被认为合法的用户输入
        /// </summary>
        public string[] AcceptWords
        {
            get
            {
                string[] array = new string[AcceptItems.Keys.Count];
                AcceptItems.Keys.CopyTo(array, 0);
                return array;
            }
        }

        /// <summary>
        /// 当用户输入错误时触发的事件
        /// </summary>
        public event InvalidInput OnErrorInput;

        /// <summary>
        ///
        /// </summary>
        /// <param name="Accept">设置合法输入与合法输入后的返回项（Key为用户可输入的文本，Value为输入特定文本后返回的值）</param>
        public ConsoleInput(Dictionary<string, object> Accept)
        {
            TitleText = "请输入：";
            AcceptItems = Accept;
            IsIgnoreCase = false;
        }

        /// <summary>
        ///
        /// </summary>
        public ConsoleInput()
        {
            TitleText = "请输入：";
            IsIgnoreCase = false;
        }

        /// <summary>
        /// 设置可接受语句
        /// </summary>
        /// <param name="keys">设置合法输入与合法输入后的返回项（Key为用户可输入的文本，Value为输入特定文本后返回的值）</param>
        public void SetAcceptItem(Dictionary<string, object> keys)
        {
            AcceptItems = keys;
        }

        private HaveBigSmallOrNone CheckItem(string text)
        {
            string key = text.ToUpper();
            string key2 = text.ToLower();
            if (AcceptItems.ContainsKey(text))
            {
                return HaveBigSmallOrNone.Have;
            }
            if (AcceptItems.ContainsKey(key))
            {
                return HaveBigSmallOrNone.Big;
            }
            if (AcceptItems.ContainsKey(key2))
            {
                return HaveBigSmallOrNone.Small;
            }
            return HaveBigSmallOrNone.None;
        }

        /// <summary>
        /// 启动用户输入
        /// </summary>
        /// <param name="Content">用户输入的提示文本</param>
        /// <returns>返回构造函数中的Accept中的特定Value</returns>
        public virtual object UserInput(string Content)
        {
            Console.WriteLine(Content);
            orgin = Console.ReadLine();
            HaveBigSmallOrNone haveBigSmallOrNone = CheckItem(orgin);
            switch (haveBigSmallOrNone)
            {
                case HaveBigSmallOrNone.Have:
                    return AcceptItems[orgin];
                case HaveBigSmallOrNone.Big:
                    if (!IsIgnoreCase)
                    {
                        return AcceptItems[orgin.ToUpper()];
                    }
                    break;
            }
            if (haveBigSmallOrNone == HaveBigSmallOrNone.Small && !IsIgnoreCase)
            {
                return AcceptItems[orgin.ToLower()];
            }
            if (this.OnErrorInput != null)
            {
                this.OnErrorInput(orgin);
            }
            else
            {
                Console.WriteLine("非法输入");
            }
            return UserInput(Content);
        }

        /// <summary>
        /// 启动用户输入
        /// </summary>
        /// <returns>返回构造函数中的Accept中的特定Value</returns>
        public virtual object UserInput()
        {
            return UserInput(TitleText);
        }

        /// <summary>
        /// 读取用户输入的整型
        /// </summary>
        /// <param name="Content">提示输入的文本</param>
        /// <param name="max">最大有效数</param>
        /// <param name="min">最小有效数</param>
        /// <returns></returns>
        public virtual int ReadInt(string Content, int? min = null, int? max = null)
        {
            Console.WriteLine(Content);
            if (!min.HasValue)
            {
                min = int.MinValue;
            }
            if (!max.HasValue)
            {
                max = int.MaxValue;
            }
            orgin = Console.ReadLine();
            int result;
            if (int.TryParse(orgin, out result) && result >= min && result <= max)
            {
                return result;
            }
            if (this.OnErrorInput != null)
            {
                this.OnErrorInput(orgin);
            }
            else
            {
                Console.WriteLine("非法输入");
            }
            return ReadInt(Content, min, max);
        }

        /// <summary>
        /// 读取用户输入的整型
        /// </summary>
        /// <param name="max">最大有效数</param>
        /// <param name="min">最小有效数</param>
        /// <returns></returns>
        public virtual int ReadInt(int? min = null, int? max = null)
        {
            return ReadInt(TitleText, min, max);
        }

        /// <summary>
        /// 读取用户输入的浮点型
        /// </summary>
        /// <param name="Content">输入提示文本</param>
        /// <param name="max">最大有效数</param>
        /// <param name="min">最小有效数</param>
        /// <returns></returns>
        public virtual double ReadDouble(string Content, double? min = null, double? max = null)
        {
            Console.WriteLine(Content);
            if (!min.HasValue)
            {
                min = double.MinValue;
            }
            if (!max.HasValue)
            {
                max = double.MaxValue;
            }
            orgin = Console.ReadLine();
            double result;
            if (double.TryParse(orgin, out result) && result >= min && result <= max)
            {
                return result;
            }
            if (this.OnErrorInput != null)
            {
                this.OnErrorInput(orgin);
            }
            else
            {
                Console.WriteLine("非法输入");
            }
            return ReadDouble(Content, min, max);
        }

        /// <summary>
        /// 读取用户输入的浮点型
        /// </summary>
        /// <param name="max">最大有效数</param>
        /// <param name="min">最小有效数</param>
        /// <returns></returns>
        public virtual double ReadDouble(double? min = null, double? max = null)
        {
            return ReadDouble(TitleText, min, max);
        }

        /// <summary>
        /// 读取用户输入的单字符
        /// </summary>
        /// <param name="Content">输入提示文本</param>
        /// <param name="max">最大有效数</param>
        /// <param name="min">最小有效数</param>
        /// <returns></returns>
        public virtual char ReadChar(string Content, char? min, char? max)
        {
            Console.WriteLine(Content);
            if (!min.HasValue)
            {
                min = '\0';
            }
            if (!max.HasValue)
            {
                max = '\uffff';
            }
            orgin = Console.ReadLine();
            bool num = orgin.Length == 1;
            char c = orgin.ToCharArray()[0];
            if (num && c >= min && c <= max)
            {
                return c;
            }
            if (this.OnErrorInput != null)
            {
                this.OnErrorInput(orgin);
            }
            else
            {
                Console.WriteLine("非法输入");
            }
            return ReadChar(Content, min, max);
        }

        /// <summary>
        /// 读取用户输入的单字符
        /// </summary>
        /// <param name="max">最大有效数</param>
        /// <param name="min">最小有效数</param>
        /// <returns></returns>
        public virtual char ReadChar(char? min = null, char? max = null)
        {
            return ReadChar(TitleText, min, max);
        }
    }


}
